/*
 * Copyright (c) 2013, SRI International
 * All rights reserved.
 * Licensed under the The BSD 3-Clause License;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 * 
 * http://opensource.org/licenses/BSD-3-Clause
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the aic-web-praise nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sri.ai.lpitools.cobra.server.servers.implementations;

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.XmlRpcRequest;
import org.apache.xmlrpc.server.PropertyHandlerMapping;
import org.apache.xmlrpc.server.RequestProcessorFactoryFactory;
import org.apache.xmlrpc.server.XmlRpcHandlerMapping;
import org.apache.xmlrpc.server.XmlRpcServer;

/**
* The connection point for a service.  This class provides basic functionality to bind an
* end point to a given server while maintaining a stateful context for the service.
* 
 * A Quick SOA terminology primer.
* A server hosts end points.  End points are service offerings which implement contracts.
* Service Contracts are interfaces which define the methods that are offered by the service.
* 
 * @author imiller
*
*/
public abstract class BasicCOBRAServerRpcEndpoint {

       private Object serviceInstance;
       private XmlRpcServer server;
       
       /**
       * An internal class which replaces the logic used to generate handlers for the XmlRpcServer
       * when responding to a request.  With this handler a service instance can be specified which
       * will be common to every call.
       * 
        * @author imiller
       *
       */
       private class BaseRequestProcessorFactoryFactory implements RequestProcessorFactoryFactory {
              
              protected final RequestProcessorFactory factory = new BaseRequestProcessorFactory();
              protected final Object service;
              
              public BaseRequestProcessorFactoryFactory(Object service) {
                     this.service = service;
              }

              private class BaseRequestProcessorFactory implements RequestProcessorFactory {
                     public Object getRequestProcessor(XmlRpcRequest xmlRpcRequest) throws XmlRpcException {
                           return service;
                     }
              }

              @SuppressWarnings("rawtypes")
              @Override
              public RequestProcessorFactory getRequestProcessorFactory(Class arg0) throws XmlRpcException {
                     return this.factory;
              }
       }
       
       /**
       * A BasicRpcEndpoint supports holding a service reference which is passed into each new
       * RPC request processor.  This allows the service to be stateful between requests without
       * the use of an external state repository (like a database).
       * 
        * @param server
       *                         The XmlRpcServer this end point will be hosted on
       * @param serviceContract
       *                         The service contract for this end point.  This should be an interface
       *                         which the end point will bind to an implementation.
       * @param serviceInstance
       *                         An instance of the service contract which will be shared among requests.
       * @throws XmlRpcException
       */
       public BasicCOBRAServerRpcEndpoint(XmlRpcServer server, Class<?> serviceContract, Object serviceInstance) throws XmlRpcException {
              XmlRpcHandlerMapping hm = server.getHandlerMapping();
              this.serviceInstance = serviceInstance;
              this.server = server;
              
              if (hm == null || !(hm instanceof PropertyHandlerMapping)) {
                     hm = new PropertyHandlerMapping();
                     server.setHandlerMapping(hm);
              } 
              PropertyHandlerMapping phm = (PropertyHandlerMapping)hm;
              phm.setRequestProcessorFactoryFactory(new BaseRequestProcessorFactoryFactory(serviceInstance));
              phm.addHandler("COBRA", serviceContract);
       }
       
       /**
       * Returns the internal instance used to spawn new service request processors.
       * @return
       *            The instance used to initialize the BasicRpcEndpoint and passed to each new request processor
       */
       protected Object getServiceInstance() {
              return this.serviceInstance;
       }
       
       /**
       * @return
       *            The RPC server this endpoint is associated with
       */
       protected XmlRpcServer getServer() {
              return this.server;
       }
}

